import { newArrayProto } from './array'
import Dep from './dep'


class Observer {
    constructor(data) {
        this.dep = new Dep()
        // data.__ob__ = this//数据加了一个标识，数据上有__ob__,被观测
        // data.__ob__.dep
        // Object.defineProperty 只能劫持已存在的属性，后增的或者删除的不知道（vue里为此写单独的api $set $delete）  
        Object.defineProperty(data, '__ob__', {
            value: this,
            enumerable: false
        })
        if (Array.isArray(data)) {//是数组
            data.__proto__ = newArrayProto // 更改数组原型为重写数组部分方法的原型
            this.observeArray(data)//监控数组中的对象
        } else {

            this.walk(data)
        }
    }

    walk(data) {// 循环对象 对属性依次劫持
        // 重新定义属性
        Object.keys(data).forEach(key => defineReactive(data, key, data[key]));
    }
    observeArray(data) {
        data.forEach(item => observe(item))
    }
}

// 深层次的嵌套会递归，递归多了性能差，不存在属性监控不到,存在的属性要重写方法 vue3=>proxy
function dependArray(value) {//
    for (let i = 0; i < value.length; i++) {
        const current = value[i];
        current.__ob__?.dep.depend()
        if (Array.isArray(current)) {
            dependArray(current)
        }

    }
}

// 
export function defineReactive(target, key, value) {// 闭包 属性劫持
    let childOb = observe(value)//对所有对象都进行属性劫持,childOp用来收集依赖
    let dep = new Dep()// 每个属性都有一个dep
    Object.defineProperty(target, key, {
        get() {
            if (Dep.target) {
                dep.depend()//让这个属性的收集器记住当前的watcher
                if (childOb) {
                    childOb.dep.depend()//让数组和对象本身也实现依赖收集
                    if (Array.isArray(value)) {// 数组里嵌套数组
                        dependArray(value)
                    }
                }
            }
            return value
        },
        set(newValue) {
            if (newValue === value) return
            observe(newValue)//劫持新赋值的对象
            value = newValue
            dep.notify()//通知该dep上的warcher更新
        }
    })
}

// 对对象进行劫持
export function observe(data) {
    //只对对象劫持
    if (typeof data !== 'object' || data == null) {
        return
    }
    // 对象被代理过了
    // 如果一个对象被劫持过了，那不需要再次被劫持了（判断一个对象是否被劫持，添加一个实例来判断是否被劫持过）
    if (data.__ob__ instanceof Observer) {
        return data.__ob__
    }
    return new Observer(data)
}